from math import *
import time

# 设虚拟电池容量为 capacity_max Wh
class VirtualBattery:
    def __init__(self, capacity_max):
        self.capacity_max = capacity_max * 1000
        # 电池当前容量：10mWh，每秒钟充入的容量为 P / 3600
        # 对照关系：0 - 400 Wh 对应电量为 0 - 100
        self.capacity = 29600*1000
        # 电量。0-10000
        self.quantity = 0
        # 电池内阻毫欧
        self.resister = 30
        # 电池当前电压（电动势），100 mV
        # 对照关系：电量 0 - 100 对应电压为 685 - 800 V
        self.voltage  = 6850
        # 当前的充电电压，100 mV
        self.charge_voltage = 0
        # 当前的充电功率
        self.power = 0

    def update_quantity(self):
        self.quantity = int(self.capacity / int(self.capacity_max / 10000))

    def update_voltage(self):
        self.voltage = 6850 + int(int(self.capacity) / int(self.capacity_max / 1150))

    def update_charge_voltage(self, power):
        #self.charge_voltage = (self.voltage + sqrt(self.voltage**2 + 4 * power * self.resister)) / 2
        # 使用近似公式
        self.charge_voltage = self.voltage + int(int(power * self.resister * 10) / self.voltage / 10)

    # 定功率充电 N 50ms，返回这 N 50ms秒的额定充电电流
    def charge_ns_with_power(self, power):
        if (self.capacity >= self.capacity_max):
            print('电池电量已充满！')
            exit(0)
        self.capacity += int(power * 25 / 18)
        if (self.capacity > self.capacity_max):
            self.capacity = self.capacity_max
        self.update_quantity()
        self.update_charge_voltage(power = power)
        amper = int(power * 10000 / self.charge_voltage / 10)
        self.update_voltage()
        self.power = power
        return amper
    
    def print_info(self, amper):
        print('{0:.2f}%, {1:.1f}/{4:.1f}V, {2}A, {3:.1f}W'.format(self.quantity / 100, self.charge_voltage / 10, amper, self.power * 100, self.voltage / 10))

if __name__ == '__main__':
    vb = VirtualBattery(30000)

    sample_time = 0.05
    duty_cycle = 500
    # power = 10000
    amper_set = 80
    voltage_set = 8000
    while (True):
        amper = vb.charge_ns_with_power(power = duty_cycle)

        if (vb.quantity / 100 > 95):
            if (voltage_set > vb.charge_voltage):
                duty_cycle += 10
            else:
                duty_cycle -= 10
            if (duty_cycle < 1):
                duty_cycle = 1
            if (duty_cycle > 1000):
                duty_cycle = 1000

        vb.print_info(amper = amper)
        time.sleep(sample_time)
